using System;
using System.Xml;
using Castle.Core.Resource;
using Castle.MicroKernel.SubSystems.Resource;

namespace Mbs.CastleContainer
{
    class XmlProcessor
    {
        private IXmlProcessorEngine engine;

        public XmlProcessor(IResourceSubSystem resourceSubSystem)
        {
            engine = new DefaultXmlProcessorEngine(resourceSubSystem);
            RegisterProcessors();
        }

        public XmlProcessor()
        {
            engine = new DefaultXmlProcessorEngine();
            RegisterProcessors();
        }

        protected virtual void RegisterProcessors()
        {
            AddElementProcessor(typeof(IfElementProcessor));
            AddElementProcessor(typeof(DefineElementProcessor));
            AddElementProcessor(typeof(UndefElementProcessor));
            AddElementProcessor(typeof(ChooseElementProcessor));
            AddElementProcessor(typeof(PropertiesElementProcessor));
            AddElementProcessor(typeof(AttributesElementProcessor));
            AddElementProcessor(typeof(IncludeElementProcessor));
            AddElementProcessor(typeof(IfProcessingInstructionProcessor));
            AddElementProcessor(typeof(DefinedProcessingInstructionProcessor));
            AddElementProcessor(typeof(UndefProcessingInstructionProcessor));
            AddElementProcessor(typeof(DefaultTextNodeProcessor));
        }

        protected void AddElementProcessor(Type t)
        {
            engine.AddNodeProcessor(t);
        }

        public XmlNode Process(XmlNode node)
        {
            try
            {
                if (node.NodeType == XmlNodeType.Document)
                {
                    node = (node as XmlDocument).DocumentElement;
                }

                engine.DispatchProcessAll(new DefaultXmlProcessorNodeList(node));

                return node;
            }
            catch (ConfigurationProcessingException)
            {
                throw;
            }
            catch (Exception ex)
            {
                String message = String.Format("Error processing element {0}, inner content {1}", node.Name, node.InnerXml);

                throw new ConfigurationProcessingException(message, ex);
            }
        }

        public XmlNode Process(IResource resource)
        {
            try
            {
                using (resource)
                {
                    XmlDocument doc = new XmlDocument();

                    doc.Load(resource.GetStreamReader());

                    engine.PushResource(resource);

                    XmlNode element = Process(doc.DocumentElement);

                    engine.PopResource();

                    return element;
                }
            }
            catch (ConfigurationProcessingException)
            {
                throw;
            }
            catch (Exception ex)
            {
                String message = String.Format("Error processing element resource {0}", resource);

                throw new ConfigurationProcessingException(message, ex);
            }
        }
    }
}
